<?php
if(!defined('IN_SONG')) exit('No direct script access allowed.');

/**
 * Class validation
 * 
 * @package libraries
 */
class Validation extends LibValidation
{
    /** 
    * Class constructor that loads the validation settings
    * @access public 
    * @param array $rules
    * @param array $messages    
    * @return void 
    */
    function __construct($rules, $messages){
        parent::__construct($rules, $messages);
    }  
    
    /** 
    * Method that validates cpf
    * @access public 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function cpf($value, $field, $params = NULL) {
        if (!preg_match("/^([0-9]){3}\.([0-9]){3}\.([0-9]){3}-([0-9]){2}$/", $value)) {
            return false;
        }
        return true;
    }
    
    /** 
    * Method that validates ZIP
    * @access public 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function cep($value, $field, $params = NULL) {
        if (!preg_match("/^[0-9]{5}-[0-9]{3}$/", $value)) {
            return false;
        }
        return true;
    }
    
    /** 
    * Phone method that validates the format (ddd) 3333-3333
    * @access private 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function telefone($value, $field, $params = NULL){
        if (!preg_match("/^0[0-9]{9}$/", $value)) {
            return false;
        }
        return true;
    }
    
    /** 
    * Method that validates the date format in Brazil 00/00/0000
    * @access public 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function databr($value, $field, $params = NULL){
        if (!preg_match("/^[0-9]{2}/[0-9]{2}/[0-9]{4}$/", $value)) {
            return false;
        }
        return true;    
    }
    
    /** 
    * Callback method
    * @access public 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function checkName($value, $field, $params = NULL) {
        if (strtolower($value) != 'hugo') {
            return true;
        }
        return false;
    }
    
    /** 
    * Example of checking the user in database
    * @access public 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    public function checkUsername($value, $field, $params = NULL) {
        
        $row = mysqli_connect ( 'server', 'username', 'password', 'database' )
                    ->query("select username from users where username = '" . $value . "'")
                        ->fetch_array(MYSQLI_ASSOC);
        
        if (!(isset($row['username']))) {
            return true;
        }
        return false;
    }
}

/** 
* 
* Class LibValidation
*                   
* @access public  
* @package libraries    
*/ 
class LibValidation extends Object
{
    
    /**      
    * Array of all errors generated by the validation 
    * @access private 
    * @name $errors
    * @var array 
    */ 
    private $errors    = array();
    
    /**      
    * Array with all data loaded for viewing post
    * @access private 
    * @name $data
    * @var array 
    */ 
    private $data = array();    
    
    /**      
    * Array that loads all configuration messages
    * @access private 
    * @name $messages
    * @var array 
    */ 
    private $messages = array();
    
    /**      
    * Array that carries all the validation rules
    * @access private 
    * @name $rules
    * @var array 
    */ 
    private $rules = array();
    
    /**      
    * Variable that sets the return of the validation
    * @access private 
    * @name $success
    * @var bool 
    */ 
    private    $success = true;
    
    /** 
    * Class constructor that loads the validation settings
    * @access public 
    * @param array $rules
    * @param array $messages    
    * @return void 
    */ 
    public function __construct($rules, $messages)
    {
        $this->messages = $messages;
        $this->rules = $rules;
        parent::__construct();
    }
    
    /** 
    * Method that validates the form
    * @access public        
    * @return void 
    */
    public function validate()
    {
        foreach($this->rules as $field => $value)
        {
            if (isset($_FILES[$field]))
            {                
                $value = $_FILES[$field];
            }
            else
            {
                $value = $this->sanitize($_POST[$field]);                
            }
            $this->setData($value, $field);
        }
                                                                
        foreach($this->rules as $field => $value)
        {                        
            $label = $value['label'];
            $rules = $value['rules'];                    
            $value = $this->getData($field);
            $check = preg_split('/\|/', $rules);                    

            foreach ($check as $function)
            {
                $callback = NULL;
                                
                if (preg_match("/:/i", $function))
                {                                    
                    list($function, $callback) = explode(":", $function);                
                }                            
                
                if (strpos($function, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $function, $matches))
                {
                    $x = explode('[', $function);
                    $function = current($x);

                    for ($x = 0; $x < count($matches['0']); $x++)
                    {                        
                        if ($matches['1'][$x] != '')
                        {
                            if (isset($_POST[$matches['1'][$x]]))
                            {
                                $params[] = $_POST[$matches['1'][$x]];
                            }
                            else
                            {
                                $param = str_ireplace("'", '', $matches['1'][$x]);
                                $param = str_ireplace('"', '', $matches['1'][$x]);
                                $params[] = $param;
                            }
                        }
                    }
                }                

                if (strpos($callback, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $callback, $matches))
                {
                    $x = explode('[', $callback);
                    $callback = current($x);
                    
                    for ($x = 0; $x < count($matches['0']); $x++)
                    {                                            
                        if ($matches['1'][$x] != '')
                        {
                            if (isset($_POST[$matches['1'][$x]]))
                            {
                                $params[] = $_POST[$matches['1'][$x]];
                            }
                            else
                            {
                                $param = str_ireplace("'", '', $matches['1'][$x]);
                                $param = str_ireplace('"', '', $matches['1'][$x]);    
                                $params[] = $param;
                            }
                        }
                    }
                }
                
                if (!isset($params)) $params = NULL;                
                    
                if (is_callable(array($this, $function)))
                {                                                
                    if (call_user_func(array($this, $function), $value, $field, $params))
                    {                                                                
                        $this->callback($this, $callback, $field, $label, $value);                                    
                    }
                    else
                    {                                                                
                        $this->success = false;
                        $this->setError($this->messages['error'][$function], $field, $label, $value);
                    }
                }
                else
                {
                    if ($function == 'required')
                    {                
                        if (!$_POST[$field])
                        {                                                            
                            $this->success = false;
                            $this->setError($this->messages['error']['required'], $field, $label, $value);
                        }
                        else
                        {
                            $this->callback($this, $callback, $field, $label, $value);                            
                        }
                    }                    
                }                
            }
        }            
        return $this->success;
    }
    
    /** 
    * Validation method return
    * @access private 
    * @param object $obj
    * @param string $callback
    * @param string $field
    * @param string $label
    * @param string $value       
    * @return void 
    */
    private function callback($obj, $callback, $field, $label, $value) {
                
        if (is_callable(array($obj, $callback)))
        {                                                            
            if (call_user_func(array($obj, $callback), $value, $field) == false)
            {                                
                $this->success = false;
                $this->setError($this->messages['error'][$callback], $field, $label, $value);
            }
        }
    }
    
    /** 
    * Method that returns the status of validation
    * @access public     
    * @return bool 
    */
    public function success()
    {
        return $this->success;
    }
    
    /** 
    * Method which sets the status of validation
    * @access public 
    * @param bool $bool       
    * @return void 
    */
    public function setSuccess($bool)
    {
        $this->success = $bool;
    }
    
    /** 
    * Method that sets values in the array $data is valid
    * @access public 
    * @param string $value
    * @param string $field    
    * @return void 
    */
    public function setData($value, $field)
    {
        $this->data[$field] = $value;
    }
    
    /** 
    * Method which sets the error level
    * @access public 
    * @param string $error
    * @param array $params    
    * @return void 
    */
    public function setLevelError($error, $params = null)
    {
        $msg = $this->messages['error'][$error];
        
        if (is_array($params))
        {
            $this->error[$error] = array('message' => $this->printf_array($msg, $params));
        }
        else
        {
            $this->error[$error] = array('message' => $msg);
        }        
    }
    
    /** 
    * Method which sets the error
    * @access public 
    * @param string $msg
    * @param string $field
    * @param string $label
    * @param string $value
    * @param array $params    
    * @return void 
    */
    public function setError($msg, $field, $label, $value, $params = null)
    {
        if (is_array($params))
        {
            $this->error[$field] = array('message' => $this->printf_array($msg, array($label, $value, $params)));
        }
        else
        {
            $this->error[$field] = array('message' => sprintf($msg, $label, $value, $params));
        }
    }
    
    /** 
    * Method that displays the messages
    * @access private 
    * @param string $format
    * @param array $arr           
    * @return string 
    */
    private function printf_array($format, $arr)
    {        
        return call_user_func_array('printf', array_merge((array)$format, $arr));
    }
    
    /** 
    * Method that retrieves data from array $data
    * @access public     
    * @param string $field       
    * @return string 
    */
    public function getData($field)
    {
        return $this->data[$field];
    }
    
    /** 
    * Method that retrieves all data from array $data
    * @access public 
    * @return array 
    */
    public function getAllData()
    {
        return $this->data;
    }
    
    /** 
    * Method that retrieves error
    * @access public     
    * @param string $field    
    * @return string 
    */
    public function getError($field)
    {
        return $this->error[$field];
    }
    
    /** 
    * Method loads all the data from array $error
    * @access public     
    * @return array 
    */
    public function getAllError()
    {
        return $this->error;
    }
    
    /** 
    * Method that validates the string lengt
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function charlen($value, $field, $params = NULL)
    {
        if(!(isset($value)) or strlen($value) < $params[0])
        {
            return false;
        }        
        return true;    
    }
    
    /** 
    * Method that validates the date and time in the format 0000-00-00 00:00:00
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function datetime($value, $field, $params = NULL)
    {
        if(!preg_match('/^(19|20)[0-9]{2}[- \/.](0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01]) [0-9]{2}:[0-9]{2}$/', $value))
        {
            return false;
        }        
        return true;    
    }

    /** 
    * Method that validates the date 0000-00-00
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function date($value, $field, $params = NULL)
    {
        if(!preg_match('/^(19|20)[0-9]{2}[- \/.](0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])$/', $value))
        {
            return false;
        }        
        return true;    
    }
    
    /** 
    * Method that confirm passwords
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function password($value, $field, $params = NULL) {
                        
        if (!isset($params[0]) or !isset($params[1])) return false;
        
        if(!(isset($value)) or strlen($value) < $params[0])    return false;            
        
        if ($value != $this->getData($params[1])) return false;
        
        return true;
    }
    
    /** 
    * Method that validates numbers
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function number($value, $field, $params = null)
    {
        return is_numeric($value) > 0 ? true : false;
    }
    
    /** 
    * Method that validates email
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function email($value, $field, $params = null)
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            return false;
        }                
        return true;
    }
    
    /** 
    * Method that optimizes url
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function urlseo($value, $field, $params = NULL)
    {                
        $this->setData($this->cleanString($value), $field);
        return true;
    }
    
    /** 
    * Method that validates url
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function url($value, $field, $params = NULL) {
        if (!filter_var($value, FILTER_VALIDATE_URL)) {
            return true;
        }
        return false;
    }
    
    /** 
    * Method that validates IP
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */        
    protected function ip($value, $field, $params = NULL) 
    {                
        if (!filter_var($value, FILTER_VALIDATE_IP)) {            
            return false;
        }        
        return true;
    }
    
    /** 
    * Method that validates select
    * @access protected 
    * @param string $value
    * @param string $field    
    * @param array $params    
    * @return bool 
    */
    protected function select($value, $field, $params = NULL)
    {                
        return $value == 0 ? false : true;
    }
    
    /** 
    * Method to clean string
    * @access private 
    * @param string $value     
    * @return string 
    */
    private function cleanString($value)
    {
    
        $acentos = array(
        'A' => '/&Agrave;|&Aacute;|&Acirc;|&Atilde;|&Auml;|&Aring;/',
        'a' => '/&agrave;|&aacute;|&acirc;|&atilde;|&auml;|&aring;/',
        'C' => '/&Ccedil;/',
        'c' => '/&ccedil;/',
        'E' => '/&Egrave;|&Eacute;|&Ecirc;|&Euml;/',
        'e' => '/&egrave;|&eacute;|&ecirc;|&euml;/',
        'I' => '/&Igrave;|&Iacute;|&Icirc;|&Iuml;/',
        'i' => '/&igrave;|&iacute;|&icirc;|&iuml;/',
        'N' => '/&Ntilde;/',
        'n' => '/&ntilde;/',
        'O' => '/&Ograve;|&Oacute;|&Ocirc;|&Otilde;|&Ouml;/',
        'o' => '/&ograve;|&oacute;|&ocirc;|&otilde;|&ouml;/',
        'U' => '/&Ugrave;|&Uacute;|&Ucirc;|&Uuml;/',
        'u' => '/&ugrave;|&uacute;|&ucirc;|&uuml;/',
        'Y' => '/&Yacute;/',
        'y' => '/&yacute;|&yuml;/',
        'a.' => '/&ordf;/',
        'o.' => '/&ordm;/',
        '-' => '/ /');

           return preg_replace($acentos,
                       array_keys($acentos),
                       htmlentities(trim($value), ENT_NOQUOTES, 'UTF-8'));
        
    }
    
    /** 
    * Method that prevents code injection attacks
    * @access private 
    * @param string $value          
    * @return string 
    */
    private function sanitize($value)
    {        
        if (!is_array($value)) {
            return filter_var($value, FILTER_SANITIZE_MAGIC_QUOTES);    
        }
        
        foreach ($value as $k => $v) {
            $value[$k] = $this->sanitize($v);
        }

        return $value;
    }    
}
?>
